package com.zty.log;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * @Author ZTY
 * @Description 业务代码的日志切面
 * @Date 21:39 2023-12-14
 **/

@Aspect
@Slf4j
@Component
@ConditionalOnProperty(name = {"log.aspect.enable"},havingValue = "true",matchIfMissing = true) //  在业务代码中的配置文件可配置是否开启
public class LogAspect {

    //  要找到切点，即要切什么东西
    //  切Controller和Service，如果有服务间调用的话还要去切RPC
    @Pointcut("execution(* com.zty.*.controller.*Controller.*(..)) || execution(* com.zty.*.service.*Service.*(..))")
    private void pointCut(){}

    //  将入参，出参打印出来
    //  环绕通知
    //  返回值要从void改成Object，不然传到Controller层的是Null
    @Around("pointCut()")   //将切点弄过来
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //  得到参数列表
        Object[] reqArgs = pjp.getArgs();
        //  将参数列表变为Json的形式，便于阅读
        String req = new Gson().toJson(reqArgs);

        //  拿到方法相关的信息，因为我要知道打印出来的是哪个方法的哪个类的出参和入参
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        //  日志格式为：类名.方法名
        String methodName = methodSignature.getDeclaringType().getName() + "." + methodSignature.getName();

        //  入参日志打印
        log.info("{}, req:{}",methodName,req);

        //  打印方法执行的耗时
        //  获得当前时间
        long startTime = System.currentTimeMillis();

        //  拦截器中的异常不要catch，要抛出去
        //  返回的是出参
        Object responseObj = pjp.proceed();
        String resp = new Gson().toJson(responseObj);

        //  获得得到出参后的时间
        long endTime = System.currentTimeMillis();

        //  出参日志打印
        log.info("{}, response:{}, costTime:{}",methodName,resp,endTime - startTime);
        return responseObj;
        /**
         * 拓展点：
         *  当前日志的操作人
         *  操作人的ip
         *  记录错误原因
         */
    }
}
